#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <MQTTClient.h>
#include <time.h>
#include "cJSON.h"
#include "shmem.h"

static struct shm_param para;

union val_t
{ 
    int b_val;  //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val;  //浮点值存储空间
};

struct student
{
    char str[64]; //可以存放所有字符型
    int key;  //唯一键值
    int type;  //数据点类型
    int dev_type;  //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val;  //变化上报后需要更新旧值
    union val_t new_val;  //从共享内存取出最新数据，放到new_val中
    int ret;  //默认为-1，采集成功后设置为0，采集失败再置-1
};

static int *total;  //指向共享内存中数据节点总个数
static struct student *node_arr;  //指向共享内存中节点缓存数组头

#define MAX_NODE 50  //最大支持学生数目
#define STD_NODE_LEN sizeof(struct student)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)
// 关键配置信息 - 在此处修改
#define BROKER_ADDRESS    "tcp://7ce449ab9c.st1.iotda-device.cn-east-3.myhuaweicloud.com:1883"  // MQTT服务器地址
#define CLIENT_ID         "68ca1c420a9ab42ae57aeae4_tea_room_0_0_2025091803"       // 客户端ID
#define SERVICE_ID        "id1"                   // 服务ID
#define USERNAME          "68ca1c420a9ab42ae57aeae4_tea_room"                       // 用户名，无则留空
#define PASSWORD          "136545888e4f2b3bff80ed6542daa2deb6a686db366e2aee591593431fb6c929"                       // 密码，无则留空
#define SUBSCRIBE_TOPIC   "$oc/devices/68ca1c420a9ab42ae57aeae4_tea_room/sys/commands/#"   // 要订阅的主题
#define PUBLISH_TOPIC     "$oc/devices/68ca1c420a9ab42ae57aeae4_tea_room/sys/properties/report"       // 要发布的主题
#define PUBLISH_INTERVAL  10                       // 发布消息的间隔(秒)
#define QOS_LEVEL         1                        // QoS级别 (0, 1, 2)
#define RETAINED_MESSAGE  0                        // 是否保留消息 (0或1)

MQTTClient client;
int connected = 0;
int running = 1;

// 生成包含温度、湿度、蜂鸣器状态、风扇状态的JSON消息
void generateJsonMessage(char *buffer, size_t bufferSize, 
                         float temperature, float humidity, 
                         const char* buzzerState, const char* fanState,const char*ledState) {
    if (buffer == NULL || bufferSize == 0) return;
// 风扇状态、蜂鸣器状态、温湿度Json格式创建
    snprintf(buffer, bufferSize, 
            "{"
            "\"services\": ["
                "{"
                "\"service_id\": \"%s\","  // 与华为云设备服务ID一致
                "\"properties\": {"
                    "\"室内温度\": %.1f,"   
                    "\"室内湿度\": %.1f,"      
                    "\"警报声\": %s,"    
                    "\"灯泡\":%s,"       
                    "\"风扇\": %s"        
                "}"
                "}"
            "]"
            "}",
            SERVICE_ID,        // 宏定义的服务ID（如"id1"）
            temperature,       // 传入的温度值（float型）
            humidity,          // 传入的湿度值（float型）
            buzzerState,       // 传入的蜂鸣器状态（如"true"）
            ledState,
            fanState);         // 传入的风扇状态（如"false"）
}

// 消息到达回调函数
// 消息到达回调函数：解析平台下发的命令并响应
int messageArrived(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    char *payloadptr = message->payload;
    
    printf("\n收到消息:\n");
    printf("  时间: %ld\n", time(NULL));
    printf("  主题: %s\n", topicName);
    printf("  内容: %.*s\n", message->payloadlen, payloadptr);
    printf("  QoS: %d\n", message->qos);
    printf("  保留: %d\n", message->retained);

    // 1. 解析JSON命令
    cJSON *root = cJSON_Parse(payloadptr);
    if (root == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            printf("JSON解析错误在: %s\n", error_ptr);
        }
        MQTTClient_freeMessage(&message);
        MQTTClient_free(topicName);
        return 1;
    }

    // 2. 提取请求ID（用于构造响应主题）
    cJSON *requestId = cJSON_GetObjectItem(root, "requestId");
    char request_id[128] = {0};
    if (requestId && requestId->type == cJSON_String) {
        strncpy(request_id, requestId->valuestring, sizeof(request_id)-1);
    }

    // 3. 提取命令方法（如控制设备的method）
    cJSON *method = cJSON_GetObjectItem(root, "method");
    if (method && method->type == cJSON_String) {
        printf("命令方法: %s\n", method->valuestring);

        // 4. 提取命令参数（params字段，包含设备控制信息）
        cJSON *params = cJSON_GetObjectItem(root, "params");
        if (params && params->type == cJSON_Object) {
            // ① 灯泡控制   
            cJSON *led = cJSON_GetObjectItem(params, "led");
            if (led && led->type == cJSON_String) {
                printf("灯泡状态: %s\n", led->valuestring);
                // TODO: 替换为实际硬件控制（如GPIO操作）
                if (strcmp(led->valuestring, "ON") == 0) {
                    printf("[硬件操作] 打开灯泡\n");
                } else if (strcmp(led->valuestring, "OFF") == 0) {
                    printf("[硬件操作] 关闭灯泡\n");
                }
            }

            // ② 风扇控制
            cJSON *fan = cJSON_GetObjectItem(params, "fan");
            if (fan && fan->type == cJSON_String) {
                printf("风扇状态: %s\n", fan->valuestring);
                // TODO: 替换为实际硬件控制
                if (strcmp(fan->valuestring, "ON") == 0) {
                    printf("[硬件操作] 打开风扇\n");
                } else if (strcmp(fan->valuestring, "OFF") == 0) {
                    printf("[硬件操作] 关闭风扇\n");
                }
            }

            // ③ 蜂鸣器控制
            cJSON *buzzer = cJSON_GetObjectItem(params, "buzzer");
            if (buzzer && buzzer->type == cJSON_String) {
                printf("蜂鸣器状态: %s\n", buzzer->valuestring);
                // TODO: 替换为实际硬件控制
                if (strcmp(buzzer->valuestring, "true") == 0) {
                    printf("[硬件操作] 打开蜂鸣器\n");
                } else if (strcmp(buzzer->valuestring, "false") == 0) {
                    printf("[硬件操作] 关闭蜂鸣器\n");
                }
            }
        }
    }

    // 5. 构造并发布「命令响应」（告知平台命令已执行）
    if (strlen(request_id) > 0) {
        char reply_topic[256];
        snprintf(reply_topic, sizeof(reply_topic), 
                "$oc/devices/68ca1c420a9ab42ae57aeae4_tea_room/sys/commands/response/request_id=%s", 
                request_id);

        // 构造响应JSON：{"result": {"code": 0, "description": "Command executed successfully"}}
        cJSON *reply_root = cJSON_CreateObject();
        cJSON *result = cJSON_CreateObject();
        cJSON_AddNumberToObject(result, "code", 0);  // 0表示成功，非0表示失败
        cJSON_AddStringToObject(result, "description", "Command executed successfully");
        cJSON_AddItemToObject(reply_root, "result", result);

        char *reply_json = cJSON_Print(reply_root);
        if (reply_json) {
            MQTTClient_message pubmsg = MQTTClient_message_initializer;
            MQTTClient_deliveryToken token;

            pubmsg.payload = reply_json;
            pubmsg.payloadlen = strlen(reply_json);
            pubmsg.qos = QOS_LEVEL;
            pubmsg.retained = RETAINED_MESSAGE;

            int rc = MQTTClient_publishMessage(client, reply_topic, &pubmsg, &token);
            if (rc == MQTTCLIENT_SUCCESS) {
                printf("已发布命令响应到主题: %s\n", reply_topic);
                printf("响应内容: %s\n", reply_json);
                MQTTClient_waitForCompletion(client, token, 1000L); // 等待发布完成
            } else {
                printf("发布命令响应失败，返回码: %d\n", rc);
            }
            free(reply_json); // 释放cJSON_Print分配的内存
        }
        cJSON_Delete(reply_root); // 释放cJSON对象内存
    }

    cJSON_Delete(root); // 释放命令JSON的内存
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

// 连接丢失回调函数
void connectionLost(void *context, char *cause) {
    printf("\n连接丢失!\n");
    if (cause)
        printf("  原因: %s\n", cause);
    printf("  尝试重新连接...\n");
    connected = 0;
}

// 交付完成回调函数
void deliveryComplete(void *context, MQTTClient_deliveryToken dt) {
    printf("消息交付完成，令牌: %d\n", dt);
}

// 连接到MQTT服务器
int connectToBroker() {
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    int rc;

    MQTTClient_create(&client, BROKER_ADDRESS, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 60;
    conn_opts.cleansession = 1;
    
    // 设置用户名密码（如果有）
    if (strlen(USERNAME) > 0) {
        conn_opts.username = USERNAME;
        if (strlen(PASSWORD) > 0) {
            conn_opts.password = PASSWORD;
        }
    }

    MQTTClient_setCallbacks(client, NULL, connectionLost, messageArrived, deliveryComplete);

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        printf("连接失败，返回代码: %d\n", rc);
        return rc;
    }
    
    printf("成功连接到 %s\n", BROKER_ADDRESS);
    connected = 1;
    return MQTTCLIENT_SUCCESS;
}

// 发布指定结构的JSON消息
int publishJsonMessage(const char *topic) {
    if (!connected) {
        printf("未连接到服务器，尝试重新连接...\n");
        if (connectToBroker() != MQTTCLIENT_SUCCESS) {
            return -1;
        }
    }
      while (running) {
        // 1. 模拟从传感器/设备获取数据（实际场景替换为真实采集逻辑）
        
        float temp = node_arr[16].new_val.f_val;   // modus
        float humi = node_arr[17].new_val.f_val;    // modus
        
       float temp = node_arr[18].new_val.f_val;   // modus
    
        float humi = node_arr[19].new_val.f_val;    // modus
        
       float temp = node_arr[9].new_val.f_val;   // 单片机
        float humi = node_arr[10].new_val.f_val;    // 单片机
       float temp = node_arr[11].new_val.f_val;   // 单片机
        float humi = node_arr[12].new_val.f_val;    // 单片机
       
       
        const char* buzzer = node_arr[13].str;  // 蜂鸣器随机状态
        const char* fan = node_arr[14].str;     // 风扇随机状态
        const char* led = node_arr[12].str;  
        


    // 生成指定结构的JSON消息
    char jsonBuffer[512];
     generateJsonMessage(jsonBuffer, sizeof(jsonBuffer), temp, humi, buzzer, fan, led);
    
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int rc;

    pubmsg.payload = jsonBuffer;
    pubmsg.payloadlen = strlen(jsonBuffer);
    pubmsg.qos = QOS_LEVEL;
    pubmsg.retained = RETAINED_MESSAGE;

    if ((rc = MQTTClient_publishMessage(client, topic, &pubmsg, &token)) != MQTTCLIENT_SUCCESS) {
        printf("发布消息失败，返回代码: %d\n", rc);
        return rc;
    }

    printf("等待消息交付...");
    if ((rc = MQTTClient_waitForCompletion(client, token, 10000L)) != MQTTCLIENT_SUCCESS) {
        printf("消息交付失败，返回代码: %d\n", rc);
        return rc;
    }
    
    printf("JSON消息已成功发布到主题: %s\n", topic);
    printf("发布内容: %s\n", jsonBuffer);
     sleep(PUBLISH_INTERVAL);
      }
    return MQTTCLIENT_SUCCESS;
}

// 订阅主题
int subscribeToTopic(const char *topic) {
    if (!connected) {
        printf("未连接到服务器，请先连接\n");
        return -1;
    }
    
    int rc;
    if ((rc = MQTTClient_subscribe(client, topic, QOS_LEVEL)) != MQTTCLIENT_SUCCESS) {
        printf("订阅主题失败，返回代码: %d\n", rc);
        return rc;
    }
    
    printf("已成功订阅主题: %s, QoS: %d\n", topic, QOS_LEVEL);
    return MQTTCLIENT_SUCCESS;
}

// 取消订阅主题
int unsubscribeFromTopic(const char *topic) {
    if (!connected) {
        printf("未连接到服务器，请先连接\n");
        return -1;
    }
    
    int rc;
    if ((rc = MQTTClient_unsubscribe(client, topic)) != MQTTCLIENT_SUCCESS) {
        printf("取消订阅主题失败，返回代码: %d\n", rc);
        return rc;
    }
    
    printf("已成功取消订阅主题: %s\n", topic);
    return MQTTCLIENT_SUCCESS;
}

// 断开连接
void disconnectFromBroker() {
    if (connected) {
        MQTTClient_disconnect(client, 10000);
        connected = 0;
        printf("已断开与服务器的连接\n");
    }
    MQTTClient_destroy(&client);
}

// 信号处理函数，用于优雅退出
void handleSignal(int signal) {
    printf("\n收到退出信号正在清理...\n");
    running = 0;
}

// 发布消息的线程函数
void *publishThread(void *arg) {
    // 初始化随机数生成器
    srand(time(NULL));
    
    while (running) {
        // 每隔指定时间发布一次JSON消息
        publishJsonMessage(PUBLISH_TOPIC);
        sleep(PUBLISH_INTERVAL);
    }
    return NULL;
}



int main(int argc, char* argv[]) {





    int ret = -1;

    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if(ret < 0)
    {
        return -1;
    }


    void *node_p = shm_getaddr(&para);
    if(node_p == NULL)
    {
        return -1;
    }

    //前4个字节存储实际的学生数目
    total = (int *)node_p;
    //后面空间存储数据点
    node_arr = (struct student *)(node_p + sizeof(int));

    
printf("%.2f\n",node_arr[16].new_val.f_val);



    pthread_t publisher;
    
    // 设置信号处理
    signal(SIGINT, handleSignal);
    signal(SIGTERM, handleSignal);
    
    printf("MQTT指定JSON结构客户端启动...\n");
    printf("配置信息:\n");
    printf("  服务器地址: %s\n", BROKER_ADDRESS);
    printf("  客户端ID: %s\n", CLIENT_ID);
    printf("  服务ID: %s\n", SERVICE_ID);
    printf("  订阅主题: %s\n", SUBSCRIBE_TOPIC);
    printf("  发布主题: %s (每%d秒)\n", PUBLISH_TOPIC, PUBLISH_INTERVAL);
    
    // 连接到MQTT服务器
    if (connectToBroker() != MQTTCLIENT_SUCCESS) {
        printf("无法连接到服务器，程序退出\n");
        return 1;
    }
    
    // 订阅主题
    if (subscribeToTopic(SUBSCRIBE_TOPIC) != MQTTCLIENT_SUCCESS) {
        printf("订阅主题失败，程序退出\n");
        disconnectFromBroker();
        return 1;
    }
    
    // 创建发布消息的线程
    if (pthread_create(&publisher, NULL, publishThread, NULL) != 0) {
        printf("创建发布线程失败\n");
        disconnectFromBroker();
        return 1;
    }
    
    // 主线程保持运行，等待消息
    printf("\n客户端运行中按Ctrl+C退出...\n");
    while (running) {
        if (!connected) {
            // 如果连接丢失，尝试重新连接
            printf("尝试重新连接到服务器...\n");
            if (connectToBroker() == MQTTCLIENT_SUCCESS) {
                subscribeToTopic(SUBSCRIBE_TOPIC);
            }
        }
        sleep(1);
    }
    
    // 清理资源
    pthread_join(publisher, NULL);
    unsubscribeFromTopic(SUBSCRIBE_TOPIC);
    disconnectFromBroker();
    
    printf("程序已退出\n");
    return 0;
}



